package Cantella::DJabberd::Store::Result::UserJid;

use base qw'DBIx::Class::Core';
use metaclass 'Reaction::Meta::Class';
use Moose;

use DJabberd::JID;
use MooseX::Types::Moose qw/ArrayRef Undef Int/;
use Reaction::Types::Core qw/NonEmptySimpleStr/;
use Cantella::DJabberd::Types qw/JID JIDNode/;

use aliased 'Cantella::DJabberd::Store::Result::User';
use aliased 'Cantella::DJabberd::Store::Result::Vhost';
use aliased 'Cantella::DJabberd::Store::Result::RosterItem';
use aliased 'Cantella::DJabberd::Store::Result::RosterGroup';
use aliased 'Cantella::DJabberd::Store::Result::LoggedMessage';
use aliased 'Cantella::DJabberd::Store::Result::JabberGroupJid';

use namespace::clean -except => [ 'meta' ];

has jid => (is => 'ro', lazy_build => 1, isa => JID );
sub _build_jid {
  my $self = shift;
  my $node = $self->node;
  my $jid = defined($node) && $node ne '' ?
    join('@',$self->node, $self->domain->hostname ) :
      $self->domain;
  DJabberd::JID->new($jid);
}

has id     => (is => 'ro', required => 1, isa => Int );
has user   => (is => 'rw', required => 1, isa => User );
has node   => (is => 'rw', required => 0, isa => JIDNode );
has domain => (is => 'rw', required => 1, isa => Vhost );

has messages      => ( isa => ArrayRef, reader => 'get_messages');
has sent_messages => ( isa => ArrayRef, reader => 'get_sent_messages');
has recieved_messages => ( isa => ArrayRef, reader => 'get_recieved_messages');
has roster_items  => ( isa => ArrayRef, reader => 'get_roster_items');
has roster_groups => ( isa => ArrayRef, reader => 'get_roster_groups');

#todo: in roster items

has jabber_groups => (
                      isa => ArrayRef,
                      reader => 'get_jabber_groups',
                      writer => 'set_jabber_groups',
                     );


{
  no warnings 'redefine';
  *get_roster_groups = sub { [ shift->roster_groups->all ] };
  *get_roster_items  = sub { [ shift->roster_items->all  ] };
  *get_jabber_groups = sub { [ shift->jabber_groups->all ] };
  *get_messages      = sub { [ shift->messages->all ] };
  *get_sent_messages = sub { [ shift->sent_messages->all ] };
  *get_recieved_messages = sub { [ shift->recieved_messages->all ] };
}

#   FROM RFC3920:
#   Each allowable portion of a JID (node identifier, domain identifier,
#   and resource identifier) MUST NOT be more than 1023 bytes in length,
#   resulting in a maximum total size (including the '@' and '/'
#   separators) of 3071 bytes

__PACKAGE__->table("user_jids");
__PACKAGE__->add_columns
  (
   id => {
            data_type => "INT",
            size => 10,
            default_value => undef,
            is_nullable => 0,
            is_auto_increment => 1,
            extra => { unsigned => 1 },
           },
   user_id => {
               data_type => "INT",
               size => 10,
               is_nullable => 0,
               extra => { unsigned => 1 },
               is_foreign_key => 1,
              },
   domain_id => {
               data_type => "INT",
               size => 10,
               is_nullable => 0,
               extra => { unsigned => 1 },
               is_foreign_key => 1,
              },
   node => {
               data_type => "VARCHAR",
               size => 255, #RFC says 1023 but this'll work for now
               default_value => "", # "" IS NOT the same as NULL ...
               is_nullable => 0,
              },
);

__PACKAGE__->set_primary_key('id');
__PACKAGE__->add_unique_constraint(jid => [qw/domain_id node/]);

__PACKAGE__->belongs_to(user => User, { id => 'user_id' } );
__PACKAGE__->belongs_to(domain => Vhost, {'foreign.id' => 'self.domain_id'});

__PACKAGE__->has_many(
                      roster_groups => RosterGroup,
                      {'foreign.owner_id' => 'self.id'}
                     );
__PACKAGE__->has_many(
                      roster_items => RosterItem,
                      {'foreign.owner_id' => 'self.id'}
                     );
__PACKAGE__->has_many(
                      in_roster_items => RosterItem,
                      {'foreign.contact_id' => 'self.id'}
                     );
__PACKAGE__->has_many(
                      jabber_group_jids => JabberGroupJid,
                      {'foreign.jid_id'  => 'self.id'}
                    );

__PACKAGE__->many_to_many(jabber_groups => 'jabber_group_jids', 'jabber_group');


#conversations
__PACKAGE__->has_many(
                      sent_messages => LoggedMessage,
                      {'foreign.from_id' => 'self.id'},
                     );
__PACKAGE__->has_many(
                      recieved_messages => LoggedMessage,
                      {'foreign.to_id' => 'self.id'},
                     );
__PACKAGE__->has_many(
                      messages => LoggedMessage,
                      [
                       {'foreign.to_id'   => 'self.id'},
                       {'foreign.from_id' => 'self.id'},
                      ]
                     );

sub display_name { shift->jid->as_bare_string }

sub set_jabber_groups {
  my ($self, $jabber_groups) = @_;

  my %set = map {$_->id => $_} @$jabber_groups;
  my %has = map {$_->id => $_} $self->jabber_groups->all;

  my @rem = grep { !exists $set{$_} } keys %has;
  my @add = grep { !exists $has{$_} } keys %set;

  return unless @add || @rem;
  $self->remove_from_jabber_groups( $has{$_} ) for @rem;
  $self->add_to_jabber_groups( $has{$_} ) for @add;
}

__PACKAGE__->meta->make_immutable(inline_constructor => 0);

1;
